Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
C# / VB.NET - [VB] TCP Client/Server
Forum - C# / VB.NET - [VB] TCP Client/Server

Avatar
Neo1986 (Ex-Member)
Pro


Messaggi: 97
Iscritto: 21/06/2010

Segnala al moderatore
Postato alle 18:09
Lunedì, 17/01/2011
Ciao a tutti!

seguendo parecchi tutorial in giro per il web, sono riuscito a realizzare una dll per la gestione della comunicazione ethernet tcp/ip, in questa ho implementato sia lato server, sia lato client.

Il mio problema è questo:

Possibile che io riesca ad inviare solamente circa 100messaggi al secondo tramite ethernet? (ogni messaggio è composto circa da 100byte).

I 2 pc interessati sono in rete ad 1gb (cavo e hub apposito)...

Avete qualche idea?

Ho provato anche a ridimensionare i buffer di lettura e scrittura in qualsiasi modo... ma niente... non cambia di una virgola.

Help ! :k:


Edit del 23/02/2011

Dopo un mese di test ho scoperto la causa, dovevo semplicemente impostare il time base, senza questo, quando si riechiede uno sleep di 1ms, il sistema operativo (non essendo real time) fa una pausetta caffè di 15ms!

Ora invio e ricevo circa 8000 parametri al secondo (stringhe al secondo)

Ultima modifica effettuata da Neo1986 il 23/02/2011 alle 9:07
PM
Avatar
HeDo (Founder Member)
Guru^2


Messaggi: 2765
Iscritto: 21/09/2007

Up
0
Down
V
Segnala al moderatore
Postato alle 18:18
Lunedì, 17/01/2011

la banda teorica di una 1Gbit è di 1024 / 8 = 128 MB/sec = 131072 KB/sec = 134217728 Byte/sec

ipotizzando una banda di 3/4 a causa di latenze varie e perdita dei cavi/switch/etc.. è cmq molto di più di quanto hai rilevato.

sicuramente il problema sta nella gestione di questi pacchetti, c'è troppo overhead di gestione o lato client o lato server.
mostra il codice e partiamo da lì.

PM
Avatar
Neo1986 (Ex-Member)
Pro


Messaggi: 97
Iscritto: 21/06/2010

Up
0
Down
V
Segnala al moderatore
Postato alle 10:28
Giovedì, 20/01/2011
Apre la connessione e avvia i thread per la scrittura e la ricezione dei dati

Codice sorgente - presumibilmente VB.NET

  1. Public Sub Thread_Server()
  2.         server = Nothing
  3.         Try
  4.  
  5.             Dim localAddr As IPAddress = IPAddress.Parse(_IndirizzoIPServer)
  6.  
  7.             server = New TcpListener(localAddr, _Porta)
  8.  
  9.             ' Start listening for client requests.
  10.             server.Start()
  11.  
  12.             ' Enter the listening loop.
  13.             While Connessione = True
  14.  
  15.                 ' Perform a blocking call to accept requests.
  16.                 ' You could also user server.AcceptSocket() here.
  17.                 Dim client As TcpClient = server.AcceptTcpClient()
  18.                 _StatoConnessione += 1
  19.  
  20.                 'creo il thread di scrittura per il client appena connesso
  21.                 ThreadScrittura = New Thread(New ParameterizedThreadStart(AddressOf Thread_Server_Write))
  22.                 ThreadScrittura.Start(client)
  23.  
  24.                 'creo il thread di lettura per il client appena connesso
  25.                 ThreadLettura = New Thread(New ParameterizedThreadStart(AddressOf Thread_Server_Read))
  26.                 ThreadLettura.Start(client)
  27.  
  28.                 'pausa per far lavorare gli altri thread
  29.                 Threading.Thread.Sleep(1)
  30.  
  31.             End While
  32.         Catch e As SocketException
  33.             '_Errore = "Eccezione Socket : " + e.ToString
  34.         Finally
  35.             server.Stop()
  36.         End Try
  37.  
  38.     End Sub



Trasmette su tcp/ip il testo contenuto nella variabile DaScrivere

Codice sorgente - presumibilmente VB.NET

  1. Public Sub Thread_Server_Write(ByVal client As Object)
  2.  
  3.         Try
  4.             Dim ClientScrittura As TcpClient = client
  5.  
  6.             ClientScrittura.NoDelay = True
  7.             ClientScrittura.SendBufferSize = 65536
  8.  
  9.             ' Get a stream object for reading and writing
  10.             Dim stream As NetworkStream = ClientScrittura.GetStream()
  11.  
  12.             While ContinuaLettura = True
  13.  
  14.                 If DaScrivere <> "" Then
  15.                     Dim msg As Byte() = System.Text.Encoding.ASCII.GetBytes(_DaScrivere + vbCrLf)
  16.  
  17.                     _DaScrivere = ""
  18.  
  19.                     ' Send back a response.
  20.                     stream.Write(msg, 0, msg.Length)
  21.  
  22.                     stream.Flush()
  23.  
  24.                 End If
  25.  
  26.                 'pausa per far lavorare gli altri thread
  27.                 Threading.Thread.Sleep(1)
  28.  
  29.             End While
  30.  
  31.             ClientScrittura.Close()
  32.  
  33.         Catch ex As Exception
  34.  
  35.         End Try
  36.  
  37.     End Sub



Riceve i dati da tcp/ip e li memorizza nella variabile DaLeggere

Codice sorgente - presumibilmente VB.NET

  1. Public Sub Thread_Server_Read(ByVal client As Object)
  2.  
  3.         Dim ClientLettura As TcpClient = client
  4.  
  5.         ClientLettura.NoDelay = True
  6.         ClientLettura.ReceiveBufferSize = 65536
  7.  
  8.         Try
  9.  
  10.             ' Buffer for reading data
  11.             Dim bytes(65536) As Byte
  12.             Dim data As String = Nothing
  13.  
  14.             data = Nothing
  15.  
  16.             ' Get a stream object for reading and writing
  17.             Dim stream As NetworkStream = ClientLettura.GetStream()
  18.  
  19.             Dim i As Int32
  20.  
  21.             ' Loop to receive all the data sent by the client.
  22.             i = stream.Read(bytes, 0, bytes.Length)
  23.  
  24.             While (i <> 0 And ContinuaLettura = True)
  25.                 ' Translate data bytes to a ASCII string.
  26.                 data = System.Text.Encoding.ASCII.GetString(bytes, 0, i)
  27.                 _DaLeggere += data
  28.  
  29.                 i = stream.Read(bytes, 0, bytes.Length)
  30.  
  31.                 'pausa per far lavorare gli altri thread
  32.                 Threading.Thread.Sleep(1)
  33.  
  34.             End While
  35.  
  36.             'aggiorno lo stato di connessione dei client
  37.             _StatoConnessione = 0
  38.  
  39.             'chiudo il client attuale visto che è stato
  40.             'disconnesso
  41.             ClientLettura.Close()
  42.  
  43.         Catch ex As Exception
  44.             'aggiorno lo stato di connessione dei client
  45.             _StatoConnessione = 0
  46.  
  47.             'chiudo il client attuale visto che è stato
  48.             'disconnesso
  49.             ClientLettura.Close()
  50.         End Try
  51.  
  52.     End Sub



Tieni presente che i buffer sono così grandi a causa di svariate prove, sia a diminuirlo che aumentarlo la quantità di dati ricevuti non cambia...

:hail:

PM
Avatar
HeDo (Founder Member)
Guru^2


Messaggi: 2765
Iscritto: 21/09/2007

Up
0
Down
V
Segnala al moderatore
Postato alle 12:18
Giovedì, 20/01/2011

allora, non hai specificato cosa contiene la variabile DaScrivere, da queste righe posso dedurre che è del testo:

Codice sorgente - presumibilmente C# / VB.NET

  1. data = System.Text.Encoding.ASCII.GetString(bytes, 0, i)
  2.                 _DaLeggere += data
  3.  
  4.                 i = stream.Read(bytes, 0, bytes.Length)
  5.  
  6.                 'pausa per far lavorare gli altri thread
  7.                 Threading.Thread.Sleep(1)



questi dati provengono presumibilmente da un file, giusto?
avrai da qualche parte ReadAllText di un file di testo molto grosso.

Ipotizzando tutto questo ti assicuro che non è il metodo migliore quello che stai adottando, il primo punto è su _DaLeggere += data.
il clr deve istanziare un nuovo oggetto stringa e copiarci dentro tutto il nuovo contenuto AD OGNI iterazione, è una pessima cosa per le performances e la memoria utilizzata.

Ad ogni modo è proprio tutto l'approcio è che inefficiente, il modo migliore per inviare una qualsiasi ingente mole di dati attraverso socket è appoggiarsi al metodo CopyTo della classe Stream. Mi spiego meglio.
Se vuoi inviare un file attraverso socket, la cosa migliore da fare è aprire uno stream verso il file SENZA leggerne il contenuto esplicitamente e chiamare una CopyTo sul networkstream. In una riga:

Codice sorgente - presumibilmente Plain Text

  1. File.OpenRead("ciao.txt").CopyTo(client.GetStream())



se vuoi rendere la cosa asincrona puoi usare la nuova TaskParallelLibrary:

Codice sorgente - presumibilmente Plain Text

  1. Parallel.Invoke(Function() File.OpenRead("ciao.txt").CopyTo(client.GetStream()))



per ricevere i dati crei uno stream in uscita verso il file che vuoi scrivere e di volta in volta ci scrivi dentro tutto il contenuto del networkstream:

Codice sorgente - presumibilmente VB.NET

  1. Dim stream As NetworkStream = client.GetStream()
  2. Dim writer As StreamWriter = File.OpenWrite("ciao.txt")
  3.  
  4. ' Va dentro un ciclo
  5. If stream.DataAvailable Then
  6.         stream.CopyTo(writer)
  7. End If



in linea di massima è sempre meglio far gestire il buffering al CLR piuttosto che provarci a mano, si elimina un layer di overhead.




PM
Avatar
Neo1986 (Ex-Member)
Pro


Messaggi: 97
Iscritto: 21/06/2010

Up
0
Down
V
Segnala al moderatore
Postato alle 16:22
Giovedì, 20/01/2011
Ok, allora penso di aver capito in parte quello che mi stai dicendo, però forse non ho detto tutto...

Quelle 3 sub sono  contenute in una dll, la variabile : DaScrivere, è come hai detto tu una proprietà string esposta dalla dll.

Non voglio assolutamente che mi scrivi tu il codice, ma...

Come potrei fare per inviare dall'esterno, del testo alla dll in modo più efficente di quello che ho fatto io?

Praticamente vorrei utilizzare questa dll in diversi programmi, magari inviare l'intero contenuto di un file di testo, oppure semplicemente passare una frase alla variabile DaScrivere (come il mio caso attuale)....

In sostanza non capisco come fare quello che hai detto:

il clr deve istanziare un nuovo oggetto stringa e copiarci dentro tutto il nuovo contenuto AD OGNI iterazione, è una pessima cosa per le performances e la memoria utilizzata.




PM
Avatar
HeDo (Founder Member)
Guru^2


Messaggi: 2765
Iscritto: 21/09/2007

Up
0
Down
V
Segnala al moderatore
Postato alle 17:44
Giovedì, 20/01/2011
Testo quotato

Postato originariamente da Neo1986:

Ok, allora penso di aver capito in parte quello che mi stai dicendo, però forse non ho detto tutto...

Quelle 3 sub sono  contenute in una dll, la variabile : DaScrivere, è come hai detto tu una proprietà string esposta dalla dll.

Non voglio assolutamente che mi scrivi tu il codice, ma...

Come potrei fare per inviare dall'esterno, del testo alla dll in modo più efficente di quello che ho fatto io?

Praticamente vorrei utilizzare questa dll in diversi programmi, magari inviare l'intero contenuto di un file di testo, oppure semplicemente passare una frase alla variabile DaScrivere (come il mio caso attuale)....

In sostanza non capisco come fare quello che hai detto:

il clr deve istanziare un nuovo oggetto stringa e copiarci dentro tutto il nuovo contenuto AD OGNI iterazione, è una pessima cosa per le performances e la memoria utilizzata.




se si inviano files ci vogliono procedure adatte ed ottimizzate per l'invio di files, se si inviano brevi frasi di testo ci vuole altro, se si inviano immagini ci vuole altro ancora, etc...

per ogni cosa c'è la sua procedura più o meno ottimizzata ma specifica per l'implementazione, cosa che tu, facendo così, ti perdi.

ad ogni modo se proprio proprio devi passare per una variabile che contiene il testo da inviare, puoi usare il memorystream:

Codice sorgente - presumibilmente C# / VB.NET

  1. MemoryStream stream = new MemoryStream(Encoding.Default.GetBytes(DaInviare));
  2.  
  3. stream.CopyTo(client.GetStream());




Ciao! era un problema di sleep del thread, non di overhead, impostando il timebase del sistema operativo a 1, tutto va al suo posto - Neo1986 - 23/02/11 09:09
PM